package com.mebs.model.logistics;

import org.jt.jet.util.JetUtils;

import javax.persistence.*;

import java.util.*;

import com.mebs.model.inventory.*;

/**
 * Created by Sergey Prasolov, sap@jensentechnologies.com Date: Feb 22, 2006, 9:00:28 PM
 */
@Entity()
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "TRUCK")
@PrimaryKeyJoinColumn(name = "Id")
public class Truck extends Transportation {
    @ManyToOne(optional = true)
    @JoinColumn(name = "StatusId")
    private TruckStatus status;

    @Column(name = "Broker", nullable = false, length = 250)
    private String broker;

    @Column(name = "BrokerLocation", nullable = true, length = 1024)
    private String brokerLocation;

    @Column(name = "BrokerContact", nullable = true, length = 250)
    private String brokerContact;

    @Column(name = "BrokerTel", nullable = true, length = 250)
    private String brokerTel;

    @Column(name = "BrokerDates", nullable = true, length = 1024)
    private String dates;

    @Column(name = "BrokerNotes", nullable = true, length = 1024)
    private String notes;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "TruckId")
    @OrderBy("ePickUp,aPickUp,eDropOff,aDropOff")
    private Set<TruckDetail> details;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "TruckId")
    @OrderBy("number")
    private Set<Box> boxes;
    
    @SuppressWarnings("unused")
	@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
    @JoinColumn(name = "TruckId")
    private Set<StatusHistory> truckStatusHistories;

    /**
     * Getters-setters
     */

    public TruckStatus getStatus()
    {
        return status;
    }

    public void setStatus(TruckStatus status)
    {
        this.status = status;
    }

    public String getBroker()
    {
        return broker;
    }

    public void setBroker(String broker)
    {
        this.broker = broker;
    }

    public String getBrokerLocation()
    {
        return brokerLocation;
    }

    public void setBrokerLocation(String brokerLocation)
    {
        this.brokerLocation = brokerLocation;
    }

    public String getBrokerContact()
    {
        return brokerContact;
    }

    public void setBrokerContact(String brokerContact)
    {
        this.brokerContact = brokerContact;
    }

    public String getBrokerTel()
    {
        return brokerTel;
    }

    public void setBrokerTel(String brokerTel)
    {
        this.brokerTel = brokerTel;
    }

    public String getDates()
    {
        return dates;
    }

    public void setDates(String dates)
    {
        this.dates = dates;
    }

    public String getNotes()
    {
        return notes;
    }

    public void setNotes(String notes)
    {
        this.notes = notes;
    }

    public Set<TruckDetail> getDetails()
    {
        return details;
    }

    public void setDetails(Set<TruckDetail> details)
    {
        this.details = details;
    }

    public Set<Box> getBoxes()
    {
        return boxes;
    }

    public void setBoxes(Set<Box> boxes)
    {
        this.boxes = boxes;
    }

    @Transient
    public Type getRequirementType()
    {
        return Type.TRUCK;
    }

//    @Transient
//    public String getSequenceNumber()
//    {
//        Calendar c = new GregorianCalendar();
//        c.setTime(getStartDate());
//        return String.format("TRUCK-%s-%05d-%02d%02d%02d",
//            getCompany().getTicker() == null ? "XXX" : getCompany().getTicker(),
//            getSequence(),
//            c.get(Calendar.YEAR) % 100,
//            c.get(Calendar.MONTH) + 1,
//            c.get(Calendar.DAY_OF_MONTH));
//    }

    @Transient
    public boolean isDeletable()
    {
        return super.isDeletable()
            && JetUtils.isEmpty(boxes)
            && JetUtils.isEmpty(details);
    }

    @Override
    public String toString()
    {
        return (this.getSequence() != null) ? this.getSequence().toString() : "";
    }

    @Transient
    public Set<StructuredBox> getStructuredBoxes()
    {
        return getConcreteBoxes(StructuredBox.class);
    }

    @Transient
    public Set<OverpackedBox> getOverpackedBoxes()
    {
        return getConcreteBoxes(OverpackedBox.class);
    }

    @Transient
    public Set<RelocationPiece> getRelocationPieces()
    {
        return getConcreteBoxes(RelocationPiece.class);
    }

    @Transient
    private <T> Set<T> getConcreteBoxes(Class<T> clazz)
    {
        Set<T> s = new HashSet<T>();
        if (JetUtils.isEmpty(boxes)) return s;

        for (Box box : boxes)
            if (box.getClass().equals(clazz))
                s.add((T) box);
        return Collections.unmodifiableSet(s);
    }

    @Transient
    public boolean isOrderExcludable(AbstractOrder order) {
        return !JetUtils.isEmpty(this.getOrders()) &&
               !this.isOrderUsed(order);
    }

    @Transient
    public boolean isOrderUsed(AbstractOrder order) {
        if(order instanceof PurchaseOrder) {
            return isPOUsed((PurchaseOrder)order);
        } else if(order instanceof RelocationOrder) {
            return isROUsed((RelocationOrder)order);
        }
        return false;  // for a case (iav)
    }

    @Transient
    public boolean isPOUsed(PurchaseOrder po) {
        if(JetUtils.isEmpty(this.boxes)) return false;
        for(Box box : this.boxes) {
            if(box instanceof StructuredBox) {
                for(BoxItem boxItem : ((StructuredBox)box).getItems()) {
                    if(boxItem.getOrderItem().getOrder().equals(po)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @Transient
    public boolean isROUsed(RelocationOrder ro) {
        if(JetUtils.isEmpty(this.boxes)) return false;
        for(Box box : this.boxes) {
            if(box instanceof RelocationPiece) {
                if(((RelocationPiece)box).getOrder().equals(ro)) {
                    return true;
                }
            }
        }
        return false;
    }

    
/*
    @Transient
    @Deprecated
    public Integer getBoxedQuantity(BoxSubItem subItem)
    {
        if (JetUtils.isEmpty(boxes)) return 0;

        int qty = 0;

        for (Box box : boxes) {
            if (box instanceof StructuredBox)
                qty += ((StructuredBox) box).getItemQuantity(subItem);
//                else if (box instanceof OverpackedBox)
//                    qty += ((OverpackedBox) box).getItemQuantity(subItem);
        }

        return qty;
    }

    @Transient
    @Deprecated
    public Integer getBoxedQuantity(OrderItem orderItem)
    {
        if (JetUtils.isEmpty(boxes)) return 0;

        int qty = 0;
        for (Box box : boxes) {
            if (box instanceof StructuredBox) {
                if (((StructuredBox) box).getItems() == null) continue;
                for (BoxItem bi : ((StructuredBox) box).getItems()) {
                    if ((bi.getOrderItem() != null)
                        && bi.getOrderItem().equals(orderItem)
                        && JetUtils.isEmpty(bi.getSubItem())) {
                        qty += bi.getQuantity();
                    }
                }
            }
        }

        return qty;
    }
*/

    @Transient
    public List<Box> getNotPackedBoxes()
    {
        List<Box> notPackedBoxes = new LinkedList<Box>();
        if (JetUtils.isEmpty(boxes)) return notPackedBoxes;

        for (Box b : this.boxes) {
            if (b.getOverpackedBox() == null) {
                notPackedBoxes.add(b);
            }
        }

        return notPackedBoxes;
    }

    @Transient
    public boolean isPiece(Box item)
    {
        return item instanceof RelocationPiece;
    }

    @Transient
    public boolean hasItem(Object item)
    {
        if (item instanceof RelocationPiece) {
            return this.hasPiece((RelocationPiece) item);
        }

        return false;
    }

    @Transient
    private boolean hasPiece(RelocationPiece piece)
    {
        if (JetUtils.isEmpty(this.boxes)) {
            return false;
        }

        return this.boxes.contains(piece);
    }

	@Transient
	public int getBoxCount() {
		return getBoxes() != null ? getBoxes().size() : 0;
	}

	@Transient
	public Box getNextBox(Box curItem){
		Box resBox = new StructuredBox();
		if (JetUtils.isEmpty(boxes)) return resBox;
		boolean isCur = false;

		for (Box b : this.boxes) {
			if(isCur){
				resBox = b;
				isCur = false;
			}
			if (b.equals(curItem)) {
                isCur = true;
            }
		}
		return resBox;
	}
}
